package com.example.seata.service;

import com.alibaba.druid.pool.DruidDataSource;
import com.example.common.utils.Statistics;
import com.example.seata.action.TCCAction;
import io.seata.rm.datasource.DataSourceProxy;
import io.seata.rm.datasource.xa.DataSourceProxyXA;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextUtil;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;

@Slf4j
@Service
public class MyServiceImpl implements MyService {

    private final DataSource dataSource1 = DataSourceBuilder.create()
            .driverClassName("com.mysql.cj.jdbc.Driver")
            .url("jdbc:mysql://localhost:3306/study-spring?serverTimezone=UTC")
            .username("root")
            .password("123456")
            .type(DruidDataSource.class)
            .build();

    private final DataSource dataSource2 = DataSourceBuilder.create()
            .driverClassName("com.mysql.cj.jdbc.Driver")
            .url("jdbc:mysql://localhost:3306/study-spring2?serverTimezone=UTC")
            .username("root")
            .password("123456")
            .type(DruidDataSource.class)
            .build();

    private final JdbcOperations jdbcOperations1;

    private final JdbcOperations jdbcOperations2;

    private final TCCAction tccAction;

    public MyServiceImpl(@Qualifier("tCCActionA") TCCAction tccAction) {
        this.tccAction = tccAction;
        jdbcOperations1 = new JdbcTemplate(dataSource1);
        jdbcOperations2 = new JdbcTemplate(dataSource2);
    }

    @GlobalTransactional
    @Override
    public void operateWithAT(){
        JdbcTemplate jdbcTemplate = new JdbcTemplate(new DataSourceProxy(dataSource1));
        JdbcTemplate jdbcTemplate2 = new JdbcTemplate(new DataSourceProxy(dataSource2));
        jdbcTemplate.update("delete from my_entity");
        jdbcTemplate2.update("delete from my_entity");
        throw new RuntimeException("模拟异常抛出");
    }

    @GlobalTransactional
    @Override
    public void operateWithTCC() {
        BusinessActionContextUtil.setContext(new BusinessActionContext());
        tccAction.prepare(BusinessActionContextUtil.getContext(), "");
    }

    @GlobalTransactional
    @Override
    public void operateWithXA(){
        JdbcOperations jdbcOperations = new JdbcTemplate(new DataSourceProxyXA(dataSource1));
        JdbcOperations jdbcOperations2 = new JdbcTemplate(new DataSourceProxyXA(dataSource2));
        jdbcOperations.update("delete from my_entity");
        jdbcOperations2.update("delete from my_entity");
        throw new RuntimeException("模拟异常抛出");
    }

    @GlobalTransactional(rollbackFor = Exception.class)
    @Override
    public void operateDataBase() {
        Statistics.logInfo(log, "operateDataBase");
        operate();
    }

    private void operate(){
        jdbcOperations1.update("insert into my_entity(id, student_name, age) values (101, '西沢 怜娜', 17)");
        jdbcOperations2.update("insert into my_entity(id, student_name, age) values (102, '中山 香里', 18)");
        jdbcOperations1.update("insert into my_entity(id, student_name, age) values (103, '屿田 唯美', 18)");
        jdbcOperations2.update("insert into my_entity(id, student_name, age) values (104, '蕾', 18)");
    }

}
